﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Mime;
using System.Reflection;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using System.Text;
using System.Web;
using Keiho;
using Keiho.Configuration;
using Keiho.Net;
using Keiho.ServiceModel;
using Keiho.Web;

[assembly: AssemblyVersion("1.0.14.0")]
[assembly: AssemblyFileVersion("1.0.14.0")]

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Service : IService
{
    private static readonly Uri StorageDirectoryUri = new Uri(SettingsUtility.GetAppSetting("WebDavDirectoryUri", ""));
    private static readonly NetworkCredential Credentials = new NetworkCredential(SettingsUtility.GetAppSetting("WebDavUsername", ""), SettingsUtility.GetAppSetting("WebDavPassword", ""));

    private static Uri GetStorageUri(string fileName)
    {
        // ファイル名を明示的に取得することによって無害化します。
        return new Uri(StorageDirectoryUri, Path.GetFileName(fileName));
    }

    public ServiceResponse<string[]> GetFileNames()
    {
        try
        {
            return new ServiceResponse<string[]> { Result = WebDavUtility.GetChildren(StorageDirectoryUri, Credentials).Where(e => !e.IsDirectory).Select(e => e.Uri.GetName()).ToArray() };
        }
        catch (Exception ex)
        {
            return new ServiceResponse<string[]> { MessageType = MessageType.Error, Message = "ファイルのリストを取得できませんでした。" };
        }
    }

    public ServiceResponse<FileEntry[]> GetFileEntries()
    {
        try
        {
            return new ServiceResponse<FileEntry[]> { Result = WebDavUtility.GetChildren(StorageDirectoryUri, Credentials).Where(e => !e.IsDirectory).Select(e => ToFileEntry(e)).ToArray() };
        }
        catch (Exception ex)
        {
            return new ServiceResponse<FileEntry[]> { MessageType = MessageType.Error, Message = "ファイルのリストを取得できませんでした。" };
        }
    }

    public ServiceResponse<byte[]> ReadFile(string fileName)
    {
        if (fileName == null) throw new ArgumentNullException("fileName");
        if (fileName.Length == 0) throw new ArgumentException("値を空にすることはできません。", "fileName");

        try
        {
            return new ServiceResponse<byte[]> { Result = WebDavUtility.Read(GetStorageUri(fileName), Credentials) };
        }
        catch (Exception ex)
        {
            return new ServiceResponse<byte[]> { MessageType = MessageType.Error, Message = string.Format("{0} を取得できませんでした。", fileName) };
        }
    }

    public void ReadFileForHtml(string fileName)
    {
        if (fileName == null) throw new ArgumentNullException("fileName");
        if (fileName.Length == 0) throw new ArgumentException("値を空にすることはできません。", "fileName");

        using (var input = WebDavUtility.OpenRead(GetStorageUri(fileName), Credentials))
        {
            HttpContext.Current.Response.RenderFile(input, null, fileName);
        }
    }

    public ServiceResponse CreateFile(string fileName, byte[] content)
    {
        if (fileName == null) throw new ArgumentNullException("fileName");
        if (fileName.Length == 0) throw new ArgumentException("値を空にすることはできません。", "fileName");

        try
        {
            WebDavUtility.Create(GetStorageUri(fileName), content, Credentials);
            return new ServiceResponse();
        }
        catch (Exception ex)
        {
            return new ServiceResponse { MessageType = MessageType.Error, Message = string.Format("{0} を追加できませんでした。", fileName) };
        }
    }

    public void CreateFileForHtml()
    {
        if (!HttpContext.Current.Request.Files.AllKeys.Contains("FileToAdd"))
        {
            throw new InvalidOperationException("ファイルが指定されていません。");
        }

        HttpPostedFile file = HttpContext.Current.Request.Files["FileToAdd"];
        if (!string.IsNullOrEmpty(file.FileName))
        {
            using (var output = WebDavUtility.OpenCreate(GetStorageUri(file.FileName), Credentials))
            {
                file.InputStream.CopyTo(output);
            }
        }

        WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.RedirectMethod;
        WebOperationContext.Current.OutgoingResponse.Location = HttpContext.Current.Request.UrlReferrer != null ? HttpContext.Current.Request.UrlReferrer.OriginalString : "../";
    }

    public ServiceResponse DeleteFile(string fileName)
    {
        if (fileName == null) throw new ArgumentNullException("fileName");
        if (fileName.Length == 0) throw new ArgumentException("値を空にすることはできません。", "fileName");

        try
        {
            WebDavUtility.Delete(GetStorageUri(fileName), Credentials);
            return new ServiceResponse();
        }
        catch (Exception ex)
        {
            return new ServiceResponse { MessageType = MessageType.Error, Message = string.Format("{0} を削除できませんでした。", fileName) };
        }
    }

    public ServiceResponse DeleteFile2(string fileName)
    {
        return DeleteFile(fileName);
    }

    private FileEntry ToFileEntry(WebDavEntry e)
    {
        return new FileEntry
        {
            FileName = e.Uri.GetName(),
            ContentLength = e.ContentLength.HasValue ? e.ContentLength.Value.ToString("N0") : null,
            LastModified = e.LastModified.HasValue ? e.LastModified.Value.ToString("yyyy-MM-dd HH:mm:ss") : null,
        };
    }
}
